from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.http import HttpResponse
from django.contrib.auth.models import User
from django.core.files import File
import openpyxl
from openpyxl.styles import Font, Alignment, PatternFill
from openpyxl.utils import get_column_letter
import pandas as pd
import os
import shutil
from PIL import Image
from io import BytesIO
from .models import Bicycle, CollegeUser


@login_required
def bike_import_template(request):
    """导出自行车导入模板Excel"""
    # 检查用户权限
    try:
        college_user = CollegeUser.objects.get(user=request.user)
        if not college_user.is_super_admin and not college_user.is_admin:
            messages.error(request, '您没有权限访问此页面。')
            return redirect('bike:bike_list')
    except CollegeUser.DoesNotExist:
        messages.error(request, '您没有管理权限，请使用前台功能。')
        return redirect('bike:bike_list')
    
    # 创建Excel工作簿
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = "自行车导入模板"
    
    # 设置表头
    headers = [
        '自行车编号', '所有人姓名', '学号', '学院', '类别', '型号', '颜色', 
        '购买日期', '联系电话', '班级', '备注', '图片文件名'
    ]
    
    # 写入表头
    for col, header in enumerate(headers, 1):
        cell = ws.cell(row=1, column=col, value=header)
        cell.font = Font(bold=True)
        cell.fill = PatternFill(start_color="CCCCCC", end_color="CCCCCC", fill_type="solid")
        cell.alignment = Alignment(horizontal="center")
    
    # 添加示例数据
    sample_data = [
        ['CS0001', '张三', '2021001', 'computer', 'mountain', '山地车', '红色', '2024-01-01', '13800138000', '计算机1班', '示例数据', 'CS0001.jpg'],
        ['EN0001', '李四', '2021002', 'engineering', 'road', '公路车', '蓝色', '2024-01-02', '13800138001', '工程1班', '示例数据', 'EN0001.jpg'],
    ]
    
    for row, data in enumerate(sample_data, 2):
        for col, value in enumerate(data, 1):
            ws.cell(row=row, column=col, value=value)
    
    # 添加学院选择说明
    ws.cell(row=5, column=1, value="学院代码说明：")
    ws.cell(row=5, column=1).font = Font(bold=True)
    
    college_choices = Bicycle.COLLEGE_CHOICES
    for i, (code, name) in enumerate(college_choices, 6):
        ws.cell(row=i, column=1, value=f"{code} - {name}")
    
    # 添加类别选择说明
    start_row = 6 + len(college_choices) + 2
    ws.cell(row=start_row, column=1, value="类别代码说明：")
    ws.cell(row=start_row, column=1).font = Font(bold=True)
    
    category_choices = Bicycle.CATEGORY_CHOICES
    for i, (code, name) in enumerate(category_choices, start_row + 1):
        ws.cell(row=i, column=1, value=f"{code} - {name}")
    
    # 设置列宽
    column_widths = [15, 12, 12, 15, 12, 12, 10, 12, 15, 12, 20, 15]
    for i, width in enumerate(column_widths, 1):
        ws.column_dimensions[get_column_letter(i)].width = width
    
    # 创建响应
    response = HttpResponse(
        content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    )
    response['Content-Disposition'] = 'attachment; filename="bicycle_import_template.xlsx"'
    
    wb.save(response)
    return response


@login_required
def bike_batch_import(request):
    """批量导入自行车"""
    # 检查用户权限
    college_user = None
    is_super_admin = False
    college = None
    
    try:
        college_user = CollegeUser.objects.get(user=request.user)
        college = college_user.college
        is_super_admin = college_user.is_super_admin
        if not college_user.is_super_admin and not college_user.is_admin:
            messages.error(request, '您没有权限访问此页面。')
            return redirect('bike:bike_list')
    except CollegeUser.DoesNotExist:
        messages.error(request, '您没有管理权限，请使用前台功能。')
        return redirect('bike:bike_list')
    
    if request.method == 'POST':
        excel_file = request.FILES.get('excel_file')
        images_zip = request.FILES.get('images_zip')
        
        if not excel_file:
            messages.error(request, '请选择要导入的Excel文件！')
            return redirect('bike:bike_batch_import')
        
        try:
            # 读取Excel文件
            df = pd.read_excel(excel_file)
            
            # 检查必要的列
            required_columns = ['自行车编号', '所有人姓名', '学号', '学院', '型号', '颜色', '类别']
            missing_columns = [col for col in required_columns if col not in df.columns]
            if missing_columns:
                messages.error(request, f'Excel文件缺少必要的列：{", ".join(missing_columns)}')
                return redirect('bike:bike_batch_import')
            
            # 处理图片文件
            image_files = {}
            if images_zip:
                import zipfile
                import tempfile
                
                # 创建临时目录
                with tempfile.TemporaryDirectory() as temp_dir:
                    # 解压ZIP文件
                    with zipfile.ZipFile(images_zip, 'r') as zip_ref:
                        zip_ref.extractall(temp_dir)
                    
                    # 遍历解压后的文件
                    for root, dirs, files in os.walk(temp_dir):
                        for file in files:
                            if file.lower().endswith(('.jpg', '.jpeg', '.png', '.gif', '.bmp')):
                                # 以文件名（不含扩展名）作为键
                                file_key = os.path.splitext(file)[0]
                                image_files[file_key] = os.path.join(root, file)
            
            success_count = 0
            error_count = 0
            errors = []
            
            # 处理每一行数据
            for index, row in df.iterrows():
                try:
                    # 检查自行车编号是否已存在
                    bike_number = str(row['自行车编号']).strip()
                    if Bicycle.objects.filter(bike_number=bike_number).exists():
                        errors.append(f"第{index+2}行：自行车编号 {bike_number} 已存在")
                        error_count += 1
                        continue
                    
                    # 检查学院代码是否有效
                    college_code = str(row['学院']).strip()
                    valid_colleges = [choice[0] for choice in Bicycle.COLLEGE_CHOICES]
                    if college_code not in valid_colleges:
                        errors.append(f"第{index+2}行：无效的学院代码 {college_code}")
                        error_count += 1
                        continue
                    
                    # 检查类别是否有效
                    category = str(row['类别']).strip()
                    valid_categories = [choice[0] for choice in Bicycle.CATEGORY_CHOICES]
                    if category not in valid_categories:
                        errors.append(f"第{index+2}行：无效的类别 {category}")
                        error_count += 1
                        continue
                    
                    # 学院管理员只能导入本学院数据
                    if not is_super_admin and college_code != college:
                        errors.append(f"第{index+2}行：您只能导入本学院的数据")
                        error_count += 1
                        continue
                    
                    # 创建自行车对象
                    bike = Bicycle(
                        bike_number=bike_number,
                        owner_name=str(row['所有人姓名']).strip(),
                        owner_student_id=str(row['学号']).strip(),
                        college=college_code,
                        category=category,
                        model=str(row['型号']).strip(),
                        color=str(row['颜色']).strip(),
                        purchase_date=row.get('购买日期', None),
                        phone_number=str(row.get('联系电话', '')).strip() or None,
                        class_name=str(row.get('班级', '')).strip() or None,
                        notes=str(row.get('备注', '')).strip() or None,
                    )
                    bike.save()
                    
                    # 处理图片
                    if '图片文件名' in row and pd.notna(row['图片文件名']):
                        image_filename = str(row['图片文件名']).strip()
                        if image_filename in image_files:
                            try:
                                # 压缩图片
                                image_path = image_files[image_filename]
                                with open(image_path, 'rb') as f:
                                    # 使用PIL压缩图片
                                    img = Image.open(f)
                                    if img.mode in ('RGBA', 'LA'):
                                        img = img.convert('RGB')
                                    
                                    # 压缩图片
                                    output = BytesIO()
                                    img.save(output, format='JPEG', quality=85, optimize=True)
                                    output.seek(0)
                                    
                                    # 保存到Django文件字段
                                    bike.image.save(
                                        f"{bike_number}.jpg",
                                        File(output),
                                        save=True
                                    )
                            except Exception as e:
                                errors.append(f"第{index+2}行：图片处理失败 - {str(e)}")
                    
                    success_count += 1
                    
                except Exception as e:
                    errors.append(f"第{index+2}行：{str(e)}")
                    error_count += 1
            
            # 显示导入结果
            if success_count > 0:
                messages.success(request, f'成功导入 {success_count} 条自行车记录！')
            if error_count > 0:
                error_message = f'导入失败 {error_count} 条记录：\n' + '\n'.join(errors[:10])
                if len(errors) > 10:
                    error_message += f'\n... 还有 {len(errors) - 10} 条错误'
                messages.error(request, error_message)
            
            return redirect('bike:admin_bike_list')
            
        except Exception as e:
            messages.error(request, f'导入文件时发生错误：{str(e)}')
            return redirect('bike:bike_batch_import')
    
    context = {
        'college_user': college_user,
        'is_super_admin': is_super_admin,
        'college': college,
    }
    
    return render(request, 'admin/bike_batch_import.html', context)
